package calao.storage.bdb;

import calao.storage.Index;
import calao.storage.Field;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;

class KeyWriter {

	final TableDatabase tdb;
	final Index index;
	final int[] valueCount;
	
	int indexPos = -1;
	Field field;
	int valuePos;
	int baseListSize;	
	TupleOutput[] keys = new TupleOutput[0];
	
	KeyWriter(TableDatabase tdb, Index index)
	{
		this.tdb = tdb;
		this.index = index;
		valueCount = new int[index.getFieldCount()];
		for (int i=0; i<valueCount.length; i++) valueCount[i] = -1;
	}
	
	void setValueCount(Field field, int count) 
	{
		valueCount[index.getPosition(field)] = count;
	}
	
	void writeValue(Field field, Object value)
	{
		checkPosition(field);
		if (indexPos==0) {
			RecordWriter.writeValue(field, value, keys[valuePos]);
		}
		else {
			int start = baseListSize*valuePos;
			int end = start+baseListSize;
			for (int i=start; i<end; i++) {
				RecordWriter.writeValue(field, value, keys[i]);
			}
		}
		valuePos++;
	}

	void writeValueFrom(Field field, TupleInput in)
	{
		checkPosition(field);
		int length = RecordReader.readValueBlockLength(in);
		if (indexPos==0) {
			keys[valuePos].writeFast(in.getBufferBytes(), in.getBufferOffset(), length);
		}
		else {
			int start = baseListSize*valuePos;
			int end = start+baseListSize;
			for (int i=start; i<end; i++) {
				keys[i].writeFast(in.getBufferBytes(), in.getBufferOffset(), length);
			}
		}
		in.skipFast(length);
		valuePos++;
	}
	
	private void checkPosition(Field field) 
	{
		if (this.field!=field) {
			int newIndexPos = index.getPosition(field);
			if (indexPos+1!=newIndexPos) throw new RuntimeException();
			this.field = field;
			indexPos = newIndexPos;
			int factor = valueCount[indexPos];
			if (factor==-1) throw new RuntimeException();
			if (indexPos==0) {
				keys = new TupleOutput[factor];
				for (int i=0; i<factor; i++) keys[i] = new TupleOutput();
			}
			else {
				TupleOutput[] newKeys = new TupleOutput[keys.length*factor];
				System.arraycopy(keys, 0, newKeys, 0, keys.length);
				for (int i=1; i<factor; i++) {
					for (int j=0; j<keys.length; j++) {
						newKeys[i*keys.length+j] = clone(keys[j]);
					}
				}
				baseListSize = keys.length;
				keys = newKeys;
			}
			valuePos = 0;
		}
	}
		
	private TupleOutput clone(TupleOutput out) 
	{
		TupleOutput result = new TupleOutput(out.getBufferBytes().clone());
		result.addSize(out.getBufferLength());
		return result;
	}
	
	boolean hasCompleteKeys()
	{
		return indexPos+1==index.getFieldCount() && valuePos==valueCount[indexPos];
	}
	
}
